.NET6 C#, LineBot, Line Messaging API, C#, dotnet core
Hihi 各位好,今天開始進入訊息的介紹了~預計連續8至9篇的內容,詳細的為各位講解 Line Bot Messaging api 傳訊機制~
傳訊息給使用者的方式簡單分為兩種
能夠傳送的訊息種類為以下 9 種
訊息的詳細介紹下一篇再開始,這篇我們先建立傳送訊息的基本機制,這樣下一篇就可以邊實作邊測試了~
這邊我直接貼上要基礎架構的 class 宣告,後面會因應情況再逐漸地加入細節~
namespace LineBotMessage.Dtos
{
public class BaseMessageDto
{
public string Type { get; set; }
}
}
namespace LineBotMessage.Enum
{
public static class MessageTypeEnum
{
public const string Text = "text";
public const string Sticker = "sticker";
public const string Image = "image";
public const string Video = "video";
public const string Audio = "audio";
public const string Location = "location";
public const string Imagemap = "imagemap";
public const string Template = "template";
public const string Flex = "flex";
}
}
using LineBotMessage.Enum;
namespace LineBotMessage.Dtos
{
public class TextMessageDto : BaseMessageDto
{
public TextMessageDto()
{
Type = MessageTypeEnum.Text;
}
public string Text { get; set; }
}
}
因為 Line 接收格式的變數名稱開頭為小寫,但 C# 習慣的命名規則 Class 變數名稱為大寫開頭,所以在傳送 Json 給 Line 的過程中 無法直接使用 JsonSerializer 做資料的處理(序列化/反序列化),所以我們需要加工一下,自己包一個 Provider 來處理 Json 轉換的問題。(會在下面的實作 用到)
新增 Providers 資料夾,並新增 JsonProvider.cs 檔案
using System.Text.Json;
using System.Text.Json.Serialization;
namespace LineBotMessage.Providers
{
public class JsonProvider
{
private JsonSerializerOptions serializeOption = new JsonSerializerOptions()
{
** PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
** };
private static JsonSerializerOptions deserializeOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
};
public string Serialize<T>(T obj)
{
return JsonSerializer.Serialize(obj, serializeOption);
}
public T Deserialize<T>(string str)
{
return JsonSerializer.Deserialize<T>(str, deserializeOptions);
}
}
}
// 宣告變數
private readonly string replyMessageUri = "https://api.line.me/v2/bot/message/reply";
private readonly string broadcastMessageUri = "https://api.line.me/v2/bot/message/broadcast";
private static HttpClient client = new HttpClient(); // 負責處理HttpRequest
private readonly JsonProvider _jsonProvider = new JsonProvider();
廣播訊息功能為在 LineBotContorller 上新增一支 API 去負責接收廣播請求並將該請求送至 LineBotService 轉換成 Line 要求的 Http request 格式送至 Line,最後成功送出廣播訊息。
namespace LineBotMessage.Dtos
{
public class BroadcastMessageRequestDto<T>
{
public List<T> Messages { get; set; }
public bool? NotificationDisabled { get; set; }
}
}
各位會發現 Messages 的型別是 List<T> 使用到了泛型,這是因為訊息的屬性非常多種的原因,在傳送時先決定好目前要傳送的訊息類型能夠比較簡單直接的實作功能。
在 LineBotService 中加入以下兩個 function
/// <summary>
/// 接收到廣播請求時,在將請求傳至 Line 前多一層處理,依據收到的 messageType 將 messages 轉換成正確的型別,這樣 Json 轉換時才能正確轉換。
/// </summary>
/// <param name="messageType"></param>
/// <param name="requestBody"></param>
public void BroadcastMessageHandler(string messageType, object requestBody)
{
string strBody = requestBody.ToString();
switch (messageType)
{
case MessageTypeEnum.Text:
var messageRequest = _jsonProvider.Deserialize<BroadcastMessageRequestDto<TextMessageDto>>(strBody);
BroadcastMessage(messageRequest);
break;
}
}
/// <summary>
/// 將廣播訊息請求送到 Line
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
public async void BroadcastMessage<T>(BroadcastMessageRequestDto<T> request)
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken); //帶入 channel access token
var json = _jsonProvider.Serialize(request);
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(broadcastMessageUri),
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(requestMessage);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
[HttpPost("SendMessage/Broadcast")]
public IActionResult Broadcast([Required] string messageType, object body)
{
_lineBotService.BroadcastMessageHandler(messageType, body);
return Ok();
}
在 Swagger 上進行廣播測試
廣播訊息傳送結果
namespace LineBotMessage.Dtos
{
public class ReplyMessageRequestDto<T>
{
public string ReplyToken { get; set; }
public List<T> Messages { get; set; }
public bool? NotificationDisabled { get;set; }
}
}
/// <summary>
/// 接收到回覆請求時,在將請求傳至 Line 前多一層處理(目前為預留)
/// </summary>
/// <param name="messageType"></param>
/// <param name="requestBody"></param>
public void ReplyMessageHandler<T>(string messageType, ReplyMessageRequestDto<T> requestBody)
{
ReplyMessage(requestBody);
}
/// <summary>
/// 將回覆訊息請求送到 Line
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
public async void ReplyMessage<T>(ReplyMessageRequestDto<T> request)
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", channelAccessToken); //帶入 channel access token
var json = _jsonProvider.Serialize(request);
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(replyMessageUri),
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
var response = await client.SendAsync(requestMessage);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
要使用回覆功能,要在接收到 webhook event 時帶入收到的 replyToken 進行回覆。
在 LineBotService - ReceiveWebhook function 中修改收到 Message Event 時的動作。
case WebhookEventTypeEnum.Message:
var replyMessage = new ReplyMessageRequestDto<TextMessageDto>()
{
ReplyToken = eventObject.ReplyToken,
Messages = new List<TextMessageDto>
{
new TextMessageDto(){Text = $"您好,您傳送了\"{eventObject.Message.Text}\"!"}
}
};
ReplyMessageHandler("text",replyMessage);
break;
撒花 ~ 今天的程式內容依舊蠻多的,希望能讓各位簡單地看懂流程建立的方式,下一篇開始會詳細的介紹 Line 提供的訊息格式並帶大家實作,中間有可能會穿插一些相關知識或是簡單的API串接,請各位期待吧!
如果想要參考今天範例程式碼的部份,下面是 Git Repo 連結,方便大家參考。
Day7_Message Introducing & Broadcasting
您好,我照著範例打,第一次有成功執行到LINE上答覆收到留言,但是關機再次上線之後不知道哪邊出了問題,LINE端就只會顯示已讀而沒有收到server端的回應訊息了,可以教我可以用什麼方式怎麼查出問題點嗎?
1.我是用Visual Studio 2022+ngrok,LINE developers上的messagingAPI驗證是回應"成功OK"的,一直持續從ngrok/inspect都可以看到確實有success回傳200 OK給LINE,也有確實把ngrok的網址正確更新到LINE developers的設定中。
2.但是不管在LINE上或者用SwaggerUI測試,LINE都收不到訊息,從Visual Studio中設定中斷點追蹤到await client.SendAsync(requestMessage)這行時,response變數就會得到StatusCode:400,ReasonPhrase: 'Bad Request'的錯誤訊息,確實沒有拋回資料,SwaggerUI和Ngrok可以看到這個POST api/LineBOt/Webhook一直處於等候中的狀態。
您好~
以收到 400 Bad Request 時,會檢查傳過去的參數名稱、型別是否有問題~
一、哈! 謝謝,我找到了,果然是我在練習修改時,不小心在WebhookEventDto類別中誤加抄了一個Id變數進去。
二、回饋一個發現給您參考: 在今天的範例中的LineBotController類別裡,有額外宣告了一個沒有用到的_jsonProvider。
收到了,感謝回饋!!
會再把它移出~